/*************************
 * MathLib 数学拓展工具类 *
 *************************/
function MathLib() { }
/**
 * calcFibonacci 计算斐波那契数列
 * @param i int order
 */
function calcFibonacci(i){
  let a = 0, s2 = 1, s1 = 1;
  i = i - 2;
  while (i-- > 0) {
    a = s1 + s2;
    s1 = s2;
    s2 = a;
  }
  return (a === 0) ? 1 : a;
}
MathLib.calcFibonacci = calcFibonacci;
/**
 * getAbsoluteValue 计算绝对值
 * @param a int number
 */
function getAbsoluteValue(a){
  return a > 0 ? a : -a;
}
MathLib.getAbsoluteValue = getAbsoluteValue;
/**
 * deg2rad 弧度转角度
 */
function deg2rad(deg) {
  return Math.PI * (deg / 180);
}
MathLib.deg2rad = deg2rad;
/**
 * cutRemainder 去除余数
 * @param n 传入被除数
 * @param dividend 传入除数
 */
function cutRemainder(n, dividend) {
  return n - (n % dividend);
}
MathLib.cutRemainder = cutRemainder;

/*********************
 * Coordinate 坐标类 *
 *********************/
function Coordinate(a,b){
  if (typeof Number(a) === "number" && !isNaN(Number(a))){
    this.x = Number(a);
    this.y = Number(b);
    this.xy = [Number(a), Number(b)];
  } else {
    switch (a.constructor.name) {
      case 'Array':
        this.x = Number(a[0]);
        this.y = Number(a[1]);
        this.xy = [this.x, this.y];
        break;
      case 'Coordinate':
        this.xy = a.xy;
        this.x = a.x;
        this.y = a.y;
        break;
      default:
        throw new TypeError("x,y is not available!");
    }
  }
}
/**
 * calcDistance 计算两个点的距离
 * @return float
 */
Coordinate.prototype.calcDistance = function(a,b){
  let oc = new Coordinate(a, b);
  let xDistance = MathLib.getAbsoluteValue(this.x - oc.x);
  let yDistance = MathLib.getAbsoluteValue(this.y - oc.y);
  let p = Math.pow;
  return p(p(xDistance,2) + p(yDistance,2),1/2);
}
/**
 * moveTo 移动点
 * @param line 线长
 * @param rad 弧度(x轴正方向为0)
 */
Coordinate.prototype.moveTo = function (line ,rad) {
  rad = {
    "right": 0.5 * Math.PI * 1,
    "down": 0.5 * Math.PI * 2,
    "left": 0.5 * Math.PI * 3,
    "up": 0.5 * Math.PI * 4,    
  }[rad] || rad;
  console.log()
  let off = [
    Math.round(Math.sin(rad) * line),
    Math.round(Math.cos(rad) * line),
  ];
  this.x += off[0];
  this.y += off[1];
  this.xy = [this.x, this.y];
  return this;
}
/**
 * clone 克隆坐标
 */
Coordinate.prototype.clone = function (){
  return new Coordinate(this);
}

/***************************
 * CalcWorkSpace 计算工作区 *
 ***************************/
function CalcWorkSpace(){
  let _MathFunctionLibArray = ['E', 'LN2', 'LN10', 'LOG2E', 
    'LOG10E', 'PI', 'SQRT1_2', 'SQRT2', 
    'abs', 'acos', 'acosh', 'asin', 'asinh', 'atan', 'atan2', 
    'atanh', 'cbrt', 'ceil', 'clz32', 'cos', 
    'cosh', 'exp', 'expm1', 'floor', 'fround', 'hypot', 'imul', 
    'log', 'log1p', 'log2', 'log10', 'max', 'min', 
    'pow', 'random', 'round', 'sign', 'sin', 'sinh',
    'sqrt', 'tan', 'tanh', 'trunc'];
  let previewDefinder = [
    'x0','x1','x2','x3','x4','x5','x6','x7','x8','x9',
    'y0','y1','y2','y3','y4','y5','y6','y7','y8','y9',
    'z0','z1','z2','z3','z4','z5','z6','z7','z8','z9',
    'r0','r1','r2','r3','r4','r5','r6','r7','r8','r9'
  ];
  this.append = function(obj){
    for (let index in obj) {
      if (obj.hasOwnProperty(index)){
        this[index] = obj[index];
      }
    }
  }
  this.append({ deg2rad, calcFibonacci, getAbsoluteValue, cutRemainder})
  for (let i = 0; i < previewDefinder.length; i++) {
    this[previewDefinder[i]] = 0;
  }
  for(let i=0; i<_MathFunctionLibArray.length; i++){
    this[_MathFunctionLibArray[i]] = Math[_MathFunctionLibArray[i]];
  }
}

module.exports = {
  MathLib, Coordinate, CalcWorkSpace,
};
